package com.btcode.security;

import com.btcode.common.StringUtil;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.apache.commons.codec.binary.Base64;

/**
 * 非对称加密服务类
 */
public class RSAService {

    private volatile static RSAService ourInstance ;

    //非对称密钥算法
    public static final String KEY_ALGORITHM = "RSA";

    /**
     * 密钥长度，DH算法的默认密钥长度是1024
     * 密钥长度必须是64的倍数，在512到65536位之间
     */
    private static final int KEY_SIZE = 512;

    /**
     * 存储公钥
     */
    private byte[] publicKey;

    /**
     * 存储私钥
     */
    private byte[] privateKey;

    public static RSAService getInstance() {
        if(ourInstance == null){
            synchronized (RSAService.class){
                if(ourInstance == null){
                    ourInstance = new RSAService();
                }
            }
        }
        return ourInstance;
    }

    private RSAService(){

        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator = null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            //初始化密钥生成器
            keyPairGenerator.initialize(KEY_SIZE);
            //生成密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            //甲方公钥
            publicKey = keyPair.getPublic().getEncoded();
            //甲方私钥
            privateKey = keyPair.getPrivate().getEncoded();
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public void setPublicKey(byte[] publicKey) {
        if(publicKey != null){
            this.publicKey = publicKey.clone();
        }
    }

    private void setPrivateKey(byte[] privateKey) {
        this.privateKey = privateKey;
    }

    /**
     * 返回base64编码的公钥
     * @return
     */
    public String getPublicKeyBase64String(){

        return StringUtil.bytesToString(Base64.encodeBase64(publicKey),"UTF-8");
    }

    /**
     * 返回base64编码的私钥
     * @return
     */
    public String getPrivateKeyBase64String(){
        return StringUtil.bytesToString(Base64.encodeBase64(publicKey));
    }

    public byte[] getPublicKey(){
        if(publicKey != null){
            return publicKey.clone();
        }
        return null;
    }

    public byte[] getPrivateKey(){
        if(privateKey != null){
            return privateKey.clone();
        }
        return null;
    }

    /**
     * 私钥加密
     * @param strToEncrypt
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public String encryptByPrivateKey(String strToEncrypt)
        throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {

            //取得私钥
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            //生成私钥
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
            //数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] result = cipher.doFinal(StringUtil.getBytes(strToEncrypt));
            return StringUtil.bytesToString(Base64.encodeBase64(result));
    }

    /**
     * 公钥加密
     * @param strToEncrypt
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public String encryptByPublicKey(String strToEncrypt)
        throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
        //产生公钥
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[] result = cipher.doFinal(StringUtil.getBytes(strToEncrypt));
        return StringUtil.bytesToString(Base64.encodeBase64(result));
    }

    /**
     * 私钥解密
     * @param strToDecrypt
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public String decryptByPrivateKey(String strToDecrypt)
        throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException{
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] result = cipher.doFinal(Base64.decodeBase64(StringUtil.getBytes( strToDecrypt)));
        return StringUtil.bytesToString(result);
    }

    public static void main(String args[])
        throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
        testBydongtai();
    }

    /**
     * 动态密钥
     */
    public static void testBydongtai()
        throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
        RSAService rsaCoder = RSAService.getInstance();

        System.out.println("公钥：" + StringUtil.bytesToString(Base64.encodeBase64(rsaCoder.publicKey)));
        System.out.println("私钥：" + StringUtil.bytesToString(Base64.encodeBase64(rsaCoder.privateKey)));

        String str = "RSA密码交换算法";
        //甲方进行数据的加密
        String code1 = rsaCoder.encryptByPublicKey(str);
        System.out.println("加密后的数据：" + code1);
        System.out.println("===========乙方使用甲方提供的公钥对数据进行解密==============");
        //乙方进行数据的解密
        String decode1 = rsaCoder.decryptByPrivateKey(code1);
        System.out.println("乙方解密后的数据：" + decode1);
    }

    public static void testByjingtai()
        throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {

        String publicKeyStr = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJk2zfx2TLEJ/h5dhsns1n664DPUfLUdrtUwR/GZ5MjPg3q9SrJN6ttNSxGsKp5gswgNMDRxuXsQgDqr267aIJcCAwEAAQ==";
        String privateKeyStr = "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAmTbN/HZMsQn+Hl2GyezWfrrgM9R8tR2u1TBH8ZnkyM+Der1Ksk3q201LEawqnmCzCA0wNHG5exCAOqvbrtoglwIDAQABAkEAmJ7KNBmXradZlt/te8nLpPP8kESzcSs/VChDEj0NdKYE3TilmdSQxdHC0qM4Mb89nVZ1Aqkq2sLYagoLPbYeqQIhAPjRHec7x/boXAXXhaJT9TFGI4lavD95zBCLrDH4ExXDAiEAnaMidy6IpACMLq54cmnVHcSEJzFt/dehlpGLGDs+mJ0CIQC2WKK+nLweQgl2qo0f+sGdm9ZdSibdqggYNBQ9Bp4N+wIgFgXolsYFiQQakZsGcNWgVJxT6jXZrBEoHiUPTb9ZK3ECIQCatcBAOfLSVlPNy+jdM97oIbA28wIHFgL6YLQ7FIonpA==";

        byte[] publicKey = Base64.decodeBase64(StringUtil.getBytes(publicKeyStr));
        byte[] privateKey = Base64.decodeBase64(StringUtil.getBytes(privateKeyStr));

        RSAService rsaCoder = RSAService.getInstance();

        rsaCoder.setPublicKey(publicKey);
        rsaCoder.setPrivateKey(privateKey);

        String str = "RSA密码交换算法";
        //甲方进行数据的加密
        String code1 = rsaCoder.encryptByPublicKey(str);
        System.out.println("加密后的数据：" + code1);
        System.out.println("===========乙方使用甲方提供的公钥对数据进行解密==============");
        //乙方进行数据的解密
        String decode1 = rsaCoder.decryptByPrivateKey(code1);
        System.out.println("乙方解密后的数据：" + decode1);

    }

}
